<?php

namespace app\service;

use share\exception\ApiException;
use share\exception\Errno;
use share\service\IpLocation;
use share\utils\Helper;

class UrlService
{

    protected $domain = [];

    protected $selector = [];
    protected $relation = [];
    protected $filterData = [];

    protected $ipInfo = null;

    private function __construct($domain, $selector, $relation, $filterData)
    {
        $this->domain = $domain;
        $this->selector = $selector;
        $this->relation = $relation;
        $this->filterData = $filterData;
    }

    private static function getInstance($domain, $selector, $relation, $filterData)
    {
        return new UrlService($domain, $selector, $relation, $filterData);
    }

    public static function getUrlInfoByFilter($ip, $vendor, $package, $version, $clientType, $client, $did)
    {
        if (!is_numeric($clientType)) {
            $clientType = UrlConfigService::getClientTypeByName($clientType);
        }
        $urlInfo = UrlConfigService::getAllConfig();
        if (empty($did) && $clientType == UrlConfigService::CLIENT_TYPE_OF_DEVICE) {
            $did = $client;
        }

        $filterData = [
                'ip' => $ip,
                'vendor' => $vendor,
                'package' => $package,
                'version' => $version,
                'clientType' => $clientType,
                'client' => $client,
                'did' => $did,
        ];

        $urlService = self::getInstance($urlInfo['domain'],$urlInfo['selector'],$urlInfo['relation'],$filterData);
        $domainInfos = $urlService->getBestMatchDomain();
        return $domainInfos;
        //     $isNeedIpInfo = self::isNeedIpInfo($urlInfo['domain']);
        // $ipInfo = null;
        // if ($isNeedIpInfo && $ip) {
        //     $ipInfo = IpLocation::info($ip);
        // }
        // $domainTypes = array_keys(UrlConfigService::getDescDomainTypeList());
        // $domainInfos = [];
        // foreach ($domainTypes as $type) {
        //     $domainMatched = self::getMatchedDomain($type, $urlInfo['domain'], [
        //         'ipInfo' => $ipInfo == null ? '' :  $ipInfo['country']['isoCode'] . '.' . $ipInfo['city'],
        //         'vendor' => $vendor,
        //         'package' => $package,
        //         'version' => $version,
        //         'clientType' => $clientType,
        //         'client' => $client,
        //         'did' => $did,
        //     ]);
        //     if (empty($domainMatched)) {
        //         continue;
        //     }
        //     $domainInfos[$type] = $domainMatched;
        // }        
    }


    public static function isNeedIpInfo($domain)
    {
        foreach ($domain as $item) {
            foreach ($item['selector'] as $selector) {
                if ($selector['type'] == UrlConfigService::SELECTOR_TYPE_OF_IP) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取最佳匹配的域名
     */
    public function getBestMatchDomain(){
        $default = $this->getDefaultDomain();
        $domainTypes = array_keys(UrlConfigService::getDescDomainTypeList());
        $result = [];
        foreach($domainTypes as $type){
            $typeId = UrlConfigService::getDomainTypeIndexByName($type);
            $relations = Helper::filter($this->relation,['domain_type' => $typeId]);            
            if(empty($relations)){
                continue;
            }
            // var_dump($type,$relations);
            foreach($relations as $rel){
                $relDomainType = $rel['domain_type'];
                $relDomainTypeName = UrlConfigService::getDomainTypeNameByIndex($relDomainType);
                // var_dump($relDomainTypeName,$result);
                if(isset($result[$relDomainTypeName])){
                    // var_dump("ignored");
                    continue;
                }
                if($rel['url_selector_type']  == UrlDomainRelationService::URL_SELECTOR_TYPE_MUTIL) {
                    $selectors = Helper::filter($this->selector,['group_id' => $rel['url_selector_id']]);
                }
                else{
                    $selectors = Helper::filter($this->selector,['id' => $rel['url_selector_id']]);
                }
                if($this->checkFilterData($selectors)){
                    $domain = Helper::filterOne($this->domain,['id' => $rel['url_domain_id']]);
                    // echo "set {$type} => ".$domain['domain']." \n";
                    $result[$type] =  $domain['domain'];                                 
                }                
            }
        }
        return array_merge($default,$result);
    }

    /**
     * 获取默认域名
     */
    public function getDefaultDomain(){
        $res = [];
        $domainTypes = array_keys(UrlConfigService::getDescDomainTypeList());
        foreach($domainTypes as $type){
            $item = Helper::filterOne($this->domain,['is_default' => 1,'type' => $type]);
            if(empty($item)) {
                throw new ApiException("URL 配置下发中未配置类型为 {$type} 的默认域名");
            }
            $res[$type] = $item['domain'];
        }
        return $res;
    }

    public function getIpInfo(){
        if($this->ipInfo === null){
            $ipData = IpLocation::info($this->filterData['ip']);
            if($ipData && isset($ipData['country']) && isset($ipData['isoCode']) && isset($ipData['city']) ){
                $this->ipInfo = $ipData['country']['isoCode'] . '.' . $ipData['city'];
            }
            else{
                $this->ipInfo = '';
            }
        }
        return $this->ipInfo;
    }

    public function checkFilterData($filters){
        $ret = true;
        if(count($filters) < 1){
            return $ret;
        }
        foreach($filters as $filter){
            $match = $filter['value'];
            $type = $filter['type'];
            // echo "compare by {$type} \n";
            if($type == UrlConfigService::SELECTOR_TYPE_OF_IP){
                $dst = $this->getIpInfo();
            }
            else{
                $dst = $this->filterData[$type];
            }
            if(!self::checkValue($dst,$match)){
                $ret = false;
                break;
            }
        }
        return $ret;
    }

    public static function checkValue($dst,$match){
        // echo "compare {$dst},{$match} \n";

        if (strtolower($dst) == strtolower($match)) {
            return true;
        }
        $ret = @preg_match('/^' . $match . '$/i', $dst); //不区分大小写
        if ($ret) {
            return true;
        }
        return false;
    }


    /**
     * 
     */
    public static function getMatchedDomain($type, $domainInfos, $matchValues)
    {
        $domainItems = Helper::filter($domainInfos, ['type' => $type]);

        $default = null;
        if (empty($domainItems)) {
            return null;
        }
        foreach ($domainItems as $item) {
            $currentDomain = $item['domain'];
            if ($item['is_default'] == 1) {
                $default = $currentDomain;
            }
            if (!isset($item['selector']) || empty($item['selector'])) {
                return $currentDomain;
            }
            if (self::checkSelectorMatched($matchValues, $item['selector'])) {
                return $currentDomain;
            }
        }
        return $default;
    }

    /**
     * 
     */
    public static function checkSelectorMatched($matchValues, $selectors)
    {

        if (empty($selectors)) {
            return true;
        }
        foreach ($selectors as $selector) {
            $type = $selector['type'];
            if (!isset($matchValues[$type])) {
                return false;
            }
            $data = $matchValues[$type];
            $matchPatterns = $selector['includes'];
            $matchResult = self::matchItems($data, $matchPatterns);
            // var_dump($data,$matchPatterns,$matchResult);
            if (!$matchResult) {
                return false;
            }
        }
        return true;
    }

    public static function matchItems($data, $patternItems)
    {
        foreach ($patternItems as $pattern) {
            if (strtolower($data) == strtolower($pattern)) {
                return true;
            }
            $ret = @preg_match('/' . $pattern . '/i', $data); //不区分大小写
            if ($ret) {
                return true;
            }
        }
        return false;
    }
}
